import os

from django.contrib import messages
from django.contrib.messages import get_messages
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from django.views.decorators.csrf import csrf_exempt

from GraphicProcess import settings
# 导入numpy包
import numpy as np
# 导入opencv包
import cv2
# 导入base64
import base64

img_path = os.path.join(settings.IMG_UPLOAD, "")
backup_path = os.path.join(settings.IMG_UPLOAD, "")
# 是否已经选择图片
yes = False


# Create your views here.
def index(request):
    return render(request, 'app1/index.html')


@csrf_exempt
def photoIn(request):
    img = request.FILES['image']
    if not img:
        return HttpResponse('请选择图片')
    # 获取图片的全文件名
    #img_name = str(time.time()) + "." + img.name.split('.').pop()
    img_name = "img." + img.name.split('.').pop()
    backup = "origin." + img.name.split('.').pop()
    global img_path, backup_path,yes
    img_path = os.path.join(settings.IMG_UPLOAD, img_name)
    backup_path = os.path.join(settings.IMG_UPLOAD, backup)
    # 写入文件
    with open(img_path, 'wb') as fp:
        # 如果上传的图片非常大，就通过chunks()方法分割成多个片段来上传
        for chunk in img.chunks():
            fp.write(chunk)
    # 备份一份原来的
        # 写入文件
    with open(backup_path, 'wb') as fp0:
        # 如果上传的图片非常大，就通过chunks()方法分割成多个片段来上传
        for chunk in img.chunks():
            fp0.write(chunk)
    # 关闭文件流
    fp.close()
    fp0.close()
    yes = True
    return HttpResponse("OK")

# 将base64地址写入文件暂存
@csrf_exempt
def photoIn2(request):
    base64url = request.POST.get('base64url')
    base64data = base64url.split(",")[1];
    img = base64.b64decode(base64data)
    global img_path
    if(yes == False):
        img_path = os.path.join(settings.IMG_UPLOAD, "img.jpg")
    # 写入文件
    with open(img_path, 'wb') as fp:
            fp.write(img)
            print("写了")
        # 关闭文件流
    fp.close()
    return HttpResponse("OK")

# 图像基本操作1
def toDo0(request):
    global img_path, yes
    if not yes:
        return HttpResponse("no")
    image = cv2.imread(img_path)
    # 要做什么操作
    todo = request.GET.get("todo")
    if todo == "undefined":
        messages.error(request, '未选择图片操作！')
        return render(request, "app1/index.html")
    print(todo)
    if todo == "brightness":
        # 获取亮度值，注意这里必须要将浮点数转为整数
        value = request.GET.get("value")
        out = brightness_change(image, int(value))
    elif todo == "contrast":
        # 获取对比度值
        value = request.GET.get("value")
        out = contrast_change(image, int(value))
    elif todo == "mean":
        out = mean(image)
    elif todo == "gaussian":
        out = gaussian(image)
    elif todo == "median":
        out = mean(image)
    elif todo == "two-sided":
        out = twoSided(image)
    else:
        return HttpResponse("test")

    cv2.imwrite(img_path, out)
    # 此处是核心部分：OPENCV转BASE64
    outimg = cv2.imencode('.jpg', out)[1]
    back = base64.b64encode(outimg)
    return HttpResponse(back, content_type='image/jpeg')

def toDo(request):
    global img_path, yes
    if not yes:
        return HttpResponse("no")
    image = cv2.imread(img_path)
    # 要做什么操作
    todo = request.GET.get("todo")
    if todo == "undefined":
        messages.error(request, '未选择图片操作！')
        return render(request, "app1/index.html")
    print(todo)
    if todo == "pepperAndSalt":
        out = pepperAndSalt(image)
    elif todo == "gas_noise":
        out = gas_noise(image)
    elif todo == "horizonFilp":
        out = horizonFilp(image)
    elif todo == "verticalFilp":
        out = verticalFilp(image)
    elif todo == "crossFilp":
        out = crossFilp(image)
    elif todo == "reset":
        out = reset()
    elif todo == "dilate":
        out = dilate()
    elif todo == "Roberts":
        out = seg_Roberts(image)
    elif todo == "Sobel":
        out = seg_Sobel(image)
    elif todo == "Laplacian":
        out = seg_Laplacian(image)
    elif todo == "Prewitt":
        out = seg_Prewitt(image)
    elif todo == "Canny":
        out = seg_Canny(image)
    elif todo == "swell":
        out = swell(image)
    elif todo == "etch":
        out = etch(image)
    elif todo == "open_compute":
        out = open_compute(image)
    elif todo == "close_compute":
        out = close_compute(image)
    else:
        return HttpResponse("TEST")

    cv2.imwrite(img_path, out)
    # 此处是核心部分：OPENCV转BASE64
    outimg = cv2.imencode('.jpg', out)[1]
    back = base64.b64encode(outimg)
    return HttpResponse(back, content_type='image/jpeg')


def photograph(request):
    return render(request, 'myapp/photograph.html')

# 重置
def reset():
    global backup_path
    image = cv2.imread(backup_path)
    return image

# 调节亮度
def brightness_change(img, brightness):
    img_t = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    h, s, v = cv2.split(img_t)
    v1 = np.clip(cv2.add(1*v, brightness), 0, 255)
    dst = np.uint8(cv2.merge((h, s, v1)))
    dst = cv2.cvtColor(dst, cv2.COLOR_HSV2BGR)
    return dst

# 调整图像的对比度
def contrast_change(img, contrast):
    img_t = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    h, s, v = cv2.split(img_t)
    v1 = np.clip(cv2.add(2 * v, contrast), 0, 255)
    dst = np.uint8(cv2.merge((h, s, v1)))
    dst = cv2.cvtColor(dst, cv2.COLOR_HSV2BGR)
    return dst

# 均值滤波
def mean(img):
    img_blur = cv2.blur(img, (5, 5))
    return img_blur

# 高斯滤波
def gaussian(img):
    img_gaussian = cv2.GaussianBlur(img, (5, 5), 0)
    return img_gaussian

# 中值滤波
def median(img):
    img_median = cv2.medianBlur(img, 5)
    return img_median

# 双边滤波
def twoSided(img):
    img_bilater = cv2.bilateralFilter(img, 9, 75, 75)
    return img_bilater

#水平镜像
def horizonFilp(image):
    horizontal = cv2.flip(image, 1, dst=None)
    return horizontal

#垂直镜像
def verticalFilp(image):
    vertical = cv2.flip(image,0,dst=None)
    return vertical
#对角镜像
def crossFilp(image):
    cross = cv2.flip(image,-1,dst=None)
    return cross

def pepperAndSalt(image):
    # 设置添加椒盐噪声的数目比例
    s_vs_p = 0.5
    # 设置添加噪声图像像素的数目
    amount = 0.04
    # 待输出的图片
    noisy_img = np.copy(image)
    # 添加salt噪声
    num_salt = np.ceil(amount * image.size * s_vs_p)
    # 设置添加噪声的坐标位置
    coords = [np.random.randint(0, i - 1, int(num_salt)) for i in image.shape]
    noisy_img[coords[0], coords[1], :] = [255, 255, 255]
    # 添加pepper噪声
    num_pepper = np.ceil(amount * image.size * (1. - s_vs_p))
    # 设置添加噪声的坐标位置
    coords = [np.random.randint(0, i - 1, int(num_pepper)) for i in image.shape]
    noisy_img[coords[0], coords[1], :] = [0, 0, 0]
    return noisy_img

# 膨胀
def dilate():
    global img_path
    image = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
    # 交叉结构元
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
    # 进行膨胀
    dilation = cv2.dilate(image, kernel)
    ######### End #########
    return dilation

def gas_noise(image):
    # 将图片的像素值归一化，存入矩阵中
    image = np.array(image / 255, dtype=float)
    # 生成正态分布的噪声，其中0表示均值，0.1表示方差
    noise = np.random.normal(0, 0.1, image.shape)
    # 将噪声叠加到图片上
    out = image + noise
    # 将图像的归一化像素值控制在0和1之间，防止噪声越界
    out = np.clip(out, 0.0, 1.0)
    # 将图像的像素值恢复到0到255之间
    out = np.uint8(out * 255)
    return out

def close_compute(image):
    # 交叉结构元
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (10, 10))
    # 进行闭运算
    close = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)
    return close

def open_compute(image):
    # 交叉结构元
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
    # 进行开运算
    open = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
    return open

def etch(image):
    # 使用一个5x5的交叉型结构元（核心在几何中心）对二值图片src进行腐蚀
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
    erosion = cv2.erode(image, kernel)
    return erosion

def swell(image):
    # 交叉结构元
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
    # 进行膨胀
    dilation = cv2.dilate(image, kernel)
    return dilation

def seg_Canny(src):
    # 1. 高斯滤波
    blur = cv2.GaussianBlur(src, (3, 3), 0)
    # 2. 灰度转换
    grayImage = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
    # 3. 求x，y方向的Sobel算子
    gradx = cv2.Sobel(grayImage, cv2.CV_16SC1, 1, 0)
    grady = cv2.Sobel(grayImage, cv2.CV_16SC1, 0, 1)
    # 4. 使用Canny函数处理图像，x,y分别是3求出来的梯度，低阈值50，高阈值150
    edge_output = cv2.Canny(gradx, grady, 50, 150)
    return edge_output
def seg_Roberts(image):
    # 1. 灰度化处理图像
    grayImage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 2. Roberts算子
    kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
    kernely = np.array([[0, -1], [1, 0]], dtype=int)
    # 3. 卷积操作
    x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
    y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
    # 4. 数据格式转换
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    return Roberts


def seg_Sobel(image):
    # 1. 灰度化处理图像
    gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 2. 求Sobel 算子
    x = cv2.Sobel(gray_img, cv2.CV_16S, 1, 0)
    y = cv2.Sobel(gray_img, cv2.CV_16S, 0, 1)
    # cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])
    # 可选参数alpha是伸缩系数，beta是加到结果上的一个值，结果返回uint类型的图像
    Scale_absX = cv2.convertScaleAbs(x)  # convert 转换  scale 缩放
    Scale_absY = cv2.convertScaleAbs(y)
    result = cv2.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)
    return result


def seg_Prewitt(img):
    img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    # 灰度化处理图像
    grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Prewitt算子
    kernelx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int)
    kernely = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
    x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
    y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
    # 转uint8
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Prewitt = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    return Prewitt


def seg_Laplacian(image):
    # 1. 灰度化处理图像
    grayImage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 2. 高斯滤波
    dst1 = cv2.GaussianBlur(grayImage, (5, 5), 0)
    # 3. 拉普拉斯算法
    dst = cv2.Laplacian(dst1, cv2.CV_16S, ksize=3)
    # 4. 数据格式转换
    Laplacian = cv2.convertScaleAbs(dst)
    return Laplacian
